using System;
using System.IO;
using System.Text;
using UnityEngine;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Security.Cryptography;

namespace offline2048.Archive
{
    public static class ArchiveService
    {
        [ThreadStatic] private static StringBuilder _cacheBuilder = new StringBuilder(1024);

        private static string _path = "";

        #region 对外接口

        /// <summary>
        /// 初始化
        /// </summary>
        public static void Init()
        {
            if (!_isInit)
            {
                _isInit = true;
#if UNITY_EDITOR
                // 注意：为了方便调试查看，编辑器下把存储目录放到项目里
                _path = UnityEngine.Application.dataPath;
#else
                _path = UnityEngine.Application.persistentDataPath;
#endif
            }
        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="archive"></param>
        public static void Register(IArchive archive)
        {
            Init();
            if (archive != null && !_archives.Contains(archive))
            {
                _archives.Add(archive);
            }
        }

        /// <summary>
        /// 注销回调
        /// </summary>
        /// <param name="archive"></param>
        public static void Unregister(IArchive archive)
        {
            if (archive != null && _archives.Contains(archive))
            {
                _archives.Remove(archive);
            }
        }

        /// <summary>
        /// 尝试获取存档
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string TryGetSave(string key)
        {
            return PlayerPrefs.GetString(key, "");
        }

        /// <summary>
        /// 注销所有回调
        /// </summary>
        /// <param name="needSave">是否需要注销前就行一次存档</param>
        public static void UnregisterAll(bool needSave = true)
        {
            if (needSave)
            {
                Save();
            }

            _archives = new List<IArchive>();
        }

        /// <summary>
        /// 读取存档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T ReadArchive<T>(string key)
        {
            Init();
            string filePath = GetSavePath(key);
            if (File.Exists(filePath) == false)
            {
                return Activator.CreateInstance<T>();
            }

            try
            {
                string content = ReadFile(filePath);
                //if (encryption)
                //{
                //    string key = CfgSystem.GetEncryptKey();
                //    content = RijndaelDecrypt(content, key);
                //}

                var result = JsonConvert.DeserializeObject<T>(content);
                if (result == null)
                {
                    Debug.LogError(
                        $"JsonConvert deserialize object is null : FILENAME {typeof(T).Name} CONTENT {content} TYPE {typeof(T)}");
                    result = Activator.CreateInstance<T>();
                }

                return result;
            }
            catch (Exception)
            {
                // 如果文件已经损坏
                if (File.Exists(filePath))
                    File.Delete(filePath);

                return Activator.CreateInstance<T>();
            }
        }

        #endregion

        /// <summary>
        /// 是否初始化
        /// </summary>
        private static bool _isInit = false;

        /// <summary>
        /// 所有存档回调
        /// </summary>
        private static List<IArchive> _archives = new List<IArchive>();

        /// <summary>
        /// 内存存档，用于对比和上一次存档是否相同
        /// </summary>
        private static Dictionary<string, string> _saveContentDic = new Dictionary<string, string>();

        /// <summary>
        /// 计时器
        /// </summary>
        private static float _timer = 0;

        /// <summary>
        /// 保存间隔修改
        /// </summary>
        public static float SaveIntervalTime = 8f;

        /// <summary>
        /// 所有注册需要存档的回调，进行一次存档
        /// </summary>
        private static void Save()
        {
            for (int i = 0; i < _archives.Count; i++)
            {
                SaveArchives(_archives[i]);
            }
        }

        /// <summary>
        /// 存档数据
        /// </summary>
        /// <param name="archive"></param>
        public static void SaveArchives(IArchive archive)
        {
            bool needSave = false;
            try
            {
                needSave = archive.IsNeedSave;
            }
            catch (System.Exception e) //异常
            {
                Debug.LogError("[ArchiveService1]:" + e.ToString());
            }

            if (needSave)
            {
                string key = string.Empty;
                string saveContent = string.Empty;
                try
                {
                    key = archive.SaveKey;
                    saveContent = GetSaveArchive(archive.SaveContent);
                    archive.IsNeedSave = false;
                }
                catch (System.Exception e) //异常
                {
                    Debug.LogError("[ArchiveService2]:" + e.ToString());
                }

                if (saveContent != null
                    && !string.IsNullOrEmpty(key)) //存档和存档key不为空
                {
                    if (!_saveContentDic.ContainsKey(key)
                        || !saveContent.Equals(_saveContentDic[key]))
                    {
                        _saveContentDic[key] = saveContent;
                        CreateFile(GetSavePath(key), saveContent);
                    }
                }
            }
        }

        /// <summary>
        /// ApplicationPause
        /// </summary>
        /// <param name="state"></param>
        private static void ApplicationPause(bool state)
        {
            Save();
        }

        /// <summary>
        /// Update
        /// </summary>
        private static void Update()
        {
            _timer += Time.deltaTime;
            if (SaveIntervalTime < _timer)
            {
                _timer = 0;
                Save();
            }
        }

        /// <summary>
        /// 存储文档
        /// </summary>
        private static string GetSaveArchive(System.Object obj)
        {
            string content = JsonConvert.SerializeObject(obj);
            //if (encryption)
            //{
            //    string key = CfgSystem.GetEncryptKey();
            //    content = RijndaelEncrypt(content, key);
            //}
            return content;
        }

        #region 文件处理

        /// <summary>
        /// 加密
        ///<param name="content">加密内容</param> 
        ///<param name="key">加密KEY，必须为32位</param> 
        /// </summary>
        private static string RijndaelEncrypt(string content, string key)
        {
            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
            byte[] dataArray = UTF8Encoding.UTF8.GetBytes(content);

            RijndaelManaged rijndael = new RijndaelManaged();
            rijndael.Key = keyArray;
            rijndael.Mode = CipherMode.ECB;
            rijndael.Padding = PaddingMode.PKCS7;
            ICryptoTransform crypto = rijndael.CreateEncryptor();

            // 返回加密后的密文
            byte[] resultArray = crypto.TransformFinalBlock(dataArray, 0, dataArray.Length);
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }

        /// <summary>
        /// 解密
        ///<param name="content">解密内容</param> 
        ///<param name="key">加密KEY，必须为32位</param> 
        /// </summary>
        private static string RijndaelDecrypt(string content, string key)
        {
            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
            byte[] dataArray = Convert.FromBase64String(content);

            RijndaelManaged rijndael = new RijndaelManaged();
            rijndael.Key = keyArray;
            rijndael.Mode = CipherMode.ECB;
            rijndael.Padding = PaddingMode.PKCS7;
            ICryptoTransform crypto = rijndael.CreateDecryptor();

            // 返回解密后的明文
            byte[] resultArray = crypto.TransformFinalBlock(dataArray, 0, dataArray.Length);
            return UTF8Encoding.UTF8.GetString(resultArray);
        }

        /// <summary>
        /// 获取存档的文件夹路径
        /// </summary>
        private static string GetRootDirectory()
        {
#if UNITY_EDITOR
            // 注意：为了方便调试查看，编辑器下把存储目录放到项目里
            string projectPath = Path.GetDirectoryName(_path);
            projectPath = GetRegularPath(projectPath);
            return Format("{0}/Savebox", projectPath);
#else
		    return Format("{0}/Savebox", _path);
#endif
        }

        /// <summary>
        /// 获取规范化的路径
        /// </summary>
        private static string GetRegularPath(string path)
        {
            return path.Replace('\\', '/').Replace("\\", "/"); //替换为Linux路径格式
        }

        /// <summary>
        /// 获取存档文件的路径
        /// </summary>
        private static string GetSavePath(string fileName)
        {
            return Format("{0}/{1}.bytes", GetRootDirectory(), fileName);
        }

        /// <summary>
        /// 格式化
        /// </summary>
        /// <param name="format"></param>
        /// <param name="arg0"></param>
        /// <returns></returns>
        private static string Format(string format, object arg0)
        {
            if (string.IsNullOrEmpty(format))
                throw new ArgumentNullException();

            if (_cacheBuilder == null)
            {
                _cacheBuilder = new StringBuilder(1024);
            }

            _cacheBuilder.Length = 0;
            _cacheBuilder.AppendFormat(format, arg0);
            return _cacheBuilder.ToString();
        }

        /// <summary>
        /// 格式化
        /// </summary>
        /// <param name="format"></param>
        /// <param name="arg0"></param>
        /// <param name="arg1"></param>
        /// <returns></returns>
        private static string Format(string format, object arg0, object arg1)
        {
            if (string.IsNullOrEmpty(format))
                throw new ArgumentNullException();

            if (_cacheBuilder == null)
            {
                _cacheBuilder = new StringBuilder(1024);
            }

            _cacheBuilder.Length = 0;
            _cacheBuilder.AppendFormat(format, arg0, arg1);
            return _cacheBuilder.ToString();
        }

        /// <summary>
        /// 创建文件
        /// </summary>
        private static void CreateFile(string filePath, string content)
        {
            // 删除旧文件
            if (File.Exists(filePath))
                File.Delete(filePath);

            // 创建文件夹路径
            CreateFileDirectory(filePath);

            // 创建新文件
            byte[] bytes = Encoding.UTF8.GetBytes(content);
            using (FileStream fs = File.Create(filePath))
            {
                fs.Write(bytes, 0, bytes.Length);
                fs.Flush();
                fs.Close();
            }
        }

        /// <summary>
        /// 创建文件的文件夹路径
        /// </summary>
        private static void CreateFileDirectory(string filePath)
        {
            // 获取文件的文件夹路径
            string directory = Path.GetDirectoryName(filePath);
            CreateDirectory(directory);
        }

        /// <summary>
        /// 创建文件夹路径
        /// </summary>
        private static void CreateDirectory(string directory)
        {
            // If the directory doesn't exist, create it.
            if (Directory.Exists(directory) == false)
                Directory.CreateDirectory(directory);
        }

        /// <summary>
        /// 读取文件
        /// </summary>
        private static string ReadFile(string filePath)
        {
            if (File.Exists(filePath) == false)
                return string.Empty;
            return File.ReadAllText(filePath, Encoding.UTF8);
        }

        #endregion
    }
}